from machine import Pin, Timer
from utime import ticks_ms
from others import PinS
import micropython


class RelayException(BaseException):
	pass


class Relay:
	ACTIVE_MODE_LOW = 0
	ACTIVE_MODE_HIGH = 1
	ACTIVE_TIME_INFINITE = 0

	def __init__(self):
		self._needDeactive = False
		self._isActived = False
		self._control = None
		self._mode = self.ACTIVE_MODE_LOW

		self._relay_timeout_timer = Timer(-1)

		pass

	def init(self, control: PinS.GPIO, mode=ACTIVE_MODE_LOW):
		if mode == self.ACTIVE_MODE_LOW:
			self._control = Pin(control, Pin.OUT, value=1)
		elif mode == self.ACTIVE_MODE_HIGH:
			self._control = Pin(control, Pin.OUT, value=0)
		else:
			raise RelayException("invalid mode value")

		self._mode = mode

	def deinit(self):
		u"""
		释放驱动程序使用的 control 针脚
		:return: 无
		"""

		self._control = None

	def active(self, delay = 3000):
		if self._control is None:
			raise RelayException("Pin control not initialized")

		self._needDeactive = False
		delay = abs(delay)

		self._pull_up()

		time_start = ticks_ms()

		self._relay_timeout_timer.init(
			mode = Timer.PERIODIC,
			period = 100,
			callback = lambda timer: micropython.schedule(self._relay_timeout_cb, (time_start, delay))
		)

	def _relay_timeout_cb(self, timer):
		time_start = timer[0]
		delay = timer[1]

		# print("callback start", time_start)

		if not self._needDeactive:
			if delay > self.ACTIVE_TIME_INFINITE:
				if (ticks_ms() - time_start) >= delay:
					self._pull_down()
					self._relay_timeout_timer.deinit()

					print("callback stopped after", ticks_ms() - time_start)
		else:
			self._pull_down()
			self._relay_timeout_timer.deinit()

			print("callback stopped after", ticks_ms() - time_start)

		# print("callback stop", ticks_ms())

	def deactive(self):
		self._needDeactive = True

	@property
	def isActived(self):
		return self._isActived and not self._needDeactive

	def _pull_up(self):
		self._control.off() if self._mode == self.ACTIVE_MODE_LOW else self._control.on()
		self._isActived = True

		print("relay actived")

	def _pull_down(self):
		self._control.on() if self._mode == self.ACTIVE_MODE_LOW else self._control.off()
		self._isActived = False

		print("relay deactived")